/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.huawei.spare.part.replace.views.replace.switch0;

import com.huawei.spare.part.replace.framework.SmartContentPresenter;
import com.huawei.spare.part.replace.framework.SmartDataBus;
import com.huawei.spare.part.replace.framework.SmartRouter;
import com.huawei.spare.part.replace.models.Configs;
import com.huawei.spare.part.replace.models.Replacement;
import com.huawei.spare.part.replace.rx.RxUtils;
import com.huawei.spare.part.replace.views.widgets.Alerts;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import org.apache.commons.io.IOUtils;
import org.controlsfx.validation.Severity;
import org.controlsfx.validation.ValidationSupport;
import org.controlsfx.validation.Validator;
import org.controlsfx.validation.decoration.GraphicValidationDecoration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.*;
import java.util.concurrent.Callable;
import java.util.regex.Matcher;

import static com.huawei.spare.part.replace.Constants.PING;
import static com.huawei.spare.part.replace.Constants.PatternIPV4;
import static com.huawei.spare.part.replace.Constants.PingReached;

/**
 * @author Woo
 */
public class SwitchPresenter extends SmartContentPresenter {

    private static final Logger log = LoggerFactory.getLogger(SwitchPresenter.class);


    @FXML TextField host;
    @FXML TextField mask;
    @FXML TextField username;
    @FXML PasswordField password;
    @FXML PasswordField ubootPwd;
    @FXML TextField runPcIP;

    @Override
    public void initialize() {
        addFormValidation();
        Platform.runLater(() -> {
            final Configs configs = SmartDataBus.get().getConfigs();
            host.textProperty().setValue(configs.getDefaultHost());
            username.textProperty().setValue(configs.getDefaultUsername());
            password.textProperty().setValue(configs.getDefaultPassword());
            ubootPwd.textProperty().setValue(configs.getDefaultPassword());
            host.requestFocus();

            final Replacement.SmmAuth smmAuth = SmartDataBus.get().replacement().getSmmAuth();
            try {
                // 获取内网IP
                InetAddress inetAddress = InetAddress.getLocalHost();
                try (final DatagramSocket socket = new DatagramSocket()) {
                    socket.connect(InetAddress.getByName(smmAuth.getSmmHost()), 22);
                    inetAddress = socket.getLocalAddress();
                }
                final String hostAddress = inetAddress.getHostAddress();
                runPcIP.textProperty().set(hostAddress);

                // 获取子网掩码
                NetworkInterface networkInterface = NetworkInterface.getByInetAddress(inetAddress);
                for (InterfaceAddress address : networkInterface.getInterfaceAddresses()) {
                    if (address.getAddress().getHostAddress().equalsIgnoreCase(hostAddress)) {
                        final short networkPrefixLength = address.getNetworkPrefixLength();
                        int shft = 0xffffffff << (32 - networkPrefixLength);
                        int oct1 = ((byte) ((shft & 0xff000000) >> 24)) & 0xff;
                        int oct2 = ((byte) ((shft & 0x00ff0000) >> 16)) & 0xff;
                        int oct3 = ((byte) ((shft & 0x0000ff00) >> 8)) & 0xff;
                        int oct4 = ((byte) (shft & 0x000000ff)) & 0xff;
                        String networkMask = oct1 + "." + oct2 + "." + oct3 + "." + oct4;
                        mask.textProperty().set(networkMask);
                    }
                }
            } catch (UnknownHostException | SocketException ex) {
                log.warn("Failed to detect local machine ip & mask", ex);
            }

//            Observable.defer((Callable<ObservableSource<?>>) () -> {
//                return Observable.just(true);
//            }).compose(RxUtils.applySchedulers()).subscribe((e) -> {});

        });
    }

    private void addFormValidation() {
        ValidationSupport support = new ValidationSupport();
        support.setValidationDecorator(new GraphicValidationDecoration());

        final Validator<Object> notEmpty = Validator.createEmptyValidator(getString("common.validate.not.empty"));
        final Validator<String> ipV4 = Validator.createRegexValidator(getString("common.validate.ipv4"), PatternIPV4, Severity.ERROR);

        support.registerValidator(host, notEmpty);
        support.registerValidator(host, ipV4);
        support.registerValidator(mask, notEmpty);
        support.registerValidator(mask, ipV4);
        support.registerValidator(username, notEmpty);
        support.registerValidator(password, notEmpty);
        support.registerValidator(ubootPwd, notEmpty);
        support.registerValidator(runPcIP, notEmpty);
        support.registerValidator(runPcIP, ipV4);

        support.invalidProperty().addListener((observable, oldValue, newValue) -> SmartRouter.get().nextStepButton().setDisable(newValue));
    }

    @Override
    public Observable<Boolean> onFinish() {
        Replacement.SwitchAuth auth = new Replacement.SwitchAuth();
        auth.setHost(host.getText());
        auth.setMask(mask.getText());
        auth.setUsername(username.getText());
        auth.setPassword(password.getText());
        auth.setUbootPassword(ubootPwd.getText());
        SmartDataBus.get().replacement().setSwitchAuth(auth);
        SmartDataBus.get().replacement().setRunPcIp(runPcIP.getText());

        loading("switch.ip.ping", false);
        return Observable.defer((Callable<ObservableSource<Boolean>>) () -> {
            try {
                String cmd = String.format(PING, auth.getHost());
                Process p1 = java.lang.Runtime.getRuntime().exec(cmd);
                final String content = IOUtils.toString(p1.getInputStream(), "GBK");
                log.info("{} \n {}", cmd, content);
                final Matcher matcher = PingReached.matcher(content);
                log.info("ping result: {}", matcher.find());
                return Observable.just(!matcher.find());
            } catch (Exception e) {
                return Observable.error(e);
            }
        }).compose(RxUtils.<Boolean>applySchedulers()).doOnError((e) -> {
            log.error("failed to test whether ip " + auth.getHost() + " is reachable", e);
            dismissLoading();
            Alerts.error("common.title.request.failed", "switch.ip.ping.failed");
        }).doOnNext((result) -> {
            dismissLoading();
            if (!result) {
                final String content = String.format(getString("switch.ip.used.content"), auth.getHost());
                Alerts.error("switch.ip.used.title", content);
            }
        });
    }
}
